// Copyright 2009 Vladimir Solomenchuk
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package net.aramzamzam.tapestry.judo.services;

import java.io.IOException;
import java.util.Locale;

import net.aramzamzam.tapestry.judo.constants.JudoConstants;
import net.aramzamzam.tapestry.judo.services.internal.ExtraModulesImpl;
import net.aramzamzam.tapestry.judo.services.internal.Helper;
import net.aramzamzam.tapestry.judo.services.internal.LayerWorker;
import net.aramzamzam.tapestry.judo.services.internal.RequireResourcesWorker;
import net.aramzamzam.tapestry.judo.services.internal.RequireWorker;
import net.aramzamzam.tapestry.judo.services.internal.WidgetServiceImpl;
import net.aramzamzam.tapestry.judo.validator.Email;
import net.aramzamzam.tapestry.judo.validator.MaxLength;
import net.aramzamzam.tapestry.judo.validator.MaxNumber;
import net.aramzamzam.tapestry.judo.validator.MinLength;
import net.aramzamzam.tapestry.judo.validator.MinNumber;
import net.aramzamzam.tapestry.judo.validator.Regexp;
import net.aramzamzam.tapestry.judo.validator.Required;

import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.SymbolConstants;
import org.apache.tapestry5.Validator;
import org.apache.tapestry5.ioc.Configuration;
import org.apache.tapestry5.ioc.MappedConfiguration;
import org.apache.tapestry5.ioc.ObjectLocator;
import org.apache.tapestry5.ioc.OrderedConfiguration;
import org.apache.tapestry5.ioc.ServiceBinder;
import org.apache.tapestry5.ioc.annotations.Inject;
import org.apache.tapestry5.ioc.annotations.Symbol;
import org.apache.tapestry5.ioc.services.SymbolSource;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.json.JSONObject;
import org.apache.tapestry5.services.AssetSource;
import org.apache.tapestry5.services.ComponentClassTransformWorker;
import org.apache.tapestry5.services.Environment;
import org.apache.tapestry5.services.EnvironmentalShadowBuilder;
import org.apache.tapestry5.services.LibraryMapping;
import org.apache.tapestry5.services.MarkupRenderer;
import org.apache.tapestry5.services.MarkupRendererFilter;
import org.apache.tapestry5.services.PartialMarkupRenderer;
import org.apache.tapestry5.services.PartialMarkupRendererFilter;
import org.apache.tapestry5.services.Request;



/**
 * dojo support module. For correct work need configuraion in application defaults:
 *   public static void contributeApplicationDefaults(
 *           MappedConfiguration<String, String> configuration)
 *   {
 *       configuration.add(DojoConstants.DOJO_ROOT, "dojo");
 *   }
 * @author solomenchuk
 *
 */
public class JudoModule {
	private final Environment environment;
	
	public JudoModule(Environment environment)
	{
		this.environment = environment;
		
	}
	
	public static void bind(ServiceBinder binder) {
    	binder.bind(ExtraModulesService.class, ExtraModulesImpl.class);
	}
	
	public void contributeMarkupRenderer(
			OrderedConfiguration<MarkupRendererFilter> configuration,
			final TypeCoercer coercer,
			@Inject @Symbol(JudoConstants.DOJO_ROOT) final String dojoRoot,
			@Inject @Symbol(JudoConstants.DOJO_XDOMAIN) final boolean isXDomain,
			@Inject @Symbol(JudoConstants.DOJO_UNCOMPRESSED) final boolean uncompressed,
			@Inject @Symbol(SymbolConstants.PRODUCTION_MODE) final boolean isProductionMode,
			@Inject @Symbol(SymbolConstants.SUPPORTED_LOCALES) final String locales,
			final ExtraModulesService extraModules,
			final SymbolSource symbolSource,
			final AssetSource assetSource,
			@Inject final Request request) {
		MarkupRendererFilter pageRenderSupport = new MarkupRendererFilter() {
			public void renderMarkup(MarkupWriter writer,
					MarkupRenderer renderer) {
				Helper builder = new Helper();
				String[] ls = locales.split(",");
				Locale locale;
				if (ls.length>0)
				    locale=new Locale(ls[0]);
				else
				    locale=Locale.getDefault();
                WidgetServiceImpl support = new WidgetServiceImpl(coercer, builder, request, dojoRoot, isXDomain, uncompressed, !isProductionMode, locale, extraModules, symbolSource, assetSource);
				
				environment.push(WidgetService.class, support);
				
				renderer.renderMarkup(writer);
				
				builder.updateDocument(writer.getDocument());
				
				environment.pop(WidgetService.class);
			}
		};

		configuration.add("WidgetService", pageRenderSupport);
	}
	
	//ajax
    public void contributePartialMarkupRenderer(
			OrderedConfiguration<PartialMarkupRendererFilter> configuration,
			final TypeCoercer coercer,
			@Inject @Symbol(JudoConstants.DOJO_ROOT) final String dojoRoot,
			@Inject @Symbol(JudoConstants.DOJO_XDOMAIN) final boolean isXDomain,
			@Inject @Symbol(JudoConstants.DOJO_UNCOMPRESSED) final boolean uncompressed,
			@Inject @Symbol(SymbolConstants.PRODUCTION_MODE) final boolean isProductionMode,
			@Inject @Symbol(SymbolConstants.SUPPORTED_LOCALES) final String locales,
			final ExtraModulesService extraModules,
			final SymbolSource symbolSource,
			final AssetSource assetSource,
			@Inject final Request request) {
		PartialMarkupRendererFilter pageRenderSupport = new PartialMarkupRendererFilter() {
			public void renderMarkup(MarkupWriter writer, JSONObject reply,
					PartialMarkupRenderer renderer) {

				String[] ls = locales.split(",");
				Locale locale;
				if (ls.length>0)
				    locale=new Locale(ls[0]);
				else
				    locale=Locale.getDefault();
				Helper builder = new Helper();
				
                WidgetServiceImpl support = new WidgetServiceImpl(coercer, builder, request, dojoRoot, isXDomain, uncompressed, !isProductionMode, locale, extraModules, symbolSource, assetSource);
				
				environment.push(WidgetService.class, support);
				
				renderer.renderMarkup(writer, reply);
				
				builder.updateDocument(writer.getDocument());
				
				environment.pop(WidgetService.class);

			}
		};


		configuration.add("DojoPageRenderSupport", pageRenderSupport);
	}
	
	public static void contributeComponentClassTransformWorker(
            OrderedConfiguration<ComponentClassTransformWorker> configuration,
            @Inject @Symbol(SymbolConstants.PRODUCTION_MODE) final boolean isProductionMode,
            ObjectLocator locator)
    {
		if (!isProductionMode)
		{
			configuration.add("JudoRequire", locator.autobuild(RequireWorker.class), "after:SetupRender");
			configuration.add("JudoRequireResources", locator.autobuild(RequireResourcesWorker.class), "after:SetupRender");
		}
		configuration.add("JudoLayer", locator.autobuild(LayerWorker.class), "after:SetupRender");
    }
	
    /**
     * Builds a proxy to the current {@link org.apache.tapestry.PageRenderSupport} inside this thread's {@link
     * Environment}.
     */
    public WidgetService buildDojoPageRenderSupport(EnvironmentalShadowBuilder builder)
    {
        return builder.build(WidgetService.class);
    }

    public static void contributeComponentClassResolver(Configuration<LibraryMapping> configuration)
	{
		configuration.add(new LibraryMapping("judo","net.aramzamzam.tapestry.judo"));
	}
    
    /**
     * Contributes the basic set of validators: <ul> <li>required</li> <li>minlength</li> <li>maxlength</li>
     * <li>min</li> <li>max</li> <li>regexp</li> </ul>
     */
    @SuppressWarnings("unchecked")
	public static void contributeFieldValidatorSource(MappedConfiguration<String, Validator> configuration)
    {
        configuration.add("judoRequired", new Required());
        configuration.add("judoRegexp", new Regexp());
        configuration.add("judoEmail", new Email());
        configuration.add("judoMinLength", new MinLength());
        configuration.add("judoMaxLength", new MaxLength());
        configuration.add("judoMin", new MinNumber());
        configuration.add("judoMax", new MaxNumber());
    }
    
    
    public static void contributeApplicationDefaults(
            MappedConfiguration<String, String> configuration) 
    		throws IOException {
    	
		configuration.add(SymbolConstants.FORM_CLIENT_LOGIC_ENABLED, "false");
    }
    
    public static void contributeFactoryDefaults(
            MappedConfiguration<String, String> configuration){
    	
    	configuration.add(JudoConstants.DOJO_ROOT, "classpath:dojo");
    	configuration.add(JudoConstants.DOJO_XDOMAIN, "false");
		configuration.add(JudoConstants.DOJO_UNCOMPRESSED, "false");
    }
}